yamotonalds
2016-11-28
「大量のIPアドレスから大まかな地域を調べる方法って無いですかね?」
🐼「ちょっと調べてみます^^」
🐼(とは言ったものの…)
分報窓での情報提供、ありがとうございます m(_ _)m
GeoLite2を試してみよう٩( 'ω' )و
GeoLite2 データベースは、無償の IP 地理位置情報データベースで、MaxMind の GeoIP2 データベースと同等ではありますが、精度の点で多少劣ります。GeoLite2 データベースは、毎月の第一火曜日にアップデートされます。
ライセンスは「クリエイティブ・コモンズ 表示-継承 3.0 非移植ライセンス」
http://dev.maxmind.com/ja/geolite2/
GeoLite2のデータをそのまま使うこともできる。
でもまあ簡単にサクッと使いたいだけなので、日本のデータだけでいいし正規化も不要。
head -1 ./GeoLite2-City-Locations-ja.csv > loc_db_only_jp.csv
grep "日本" ./GeoLite2-City-Locations-ja.csv >> loc_db_only_jp.csv
q -H -d',' "select ip_rule.network,\
loc_jp.subdivision_1_name || loc_jp.city_name \
from ./GeoLite2-City-Blocks-IPv4.csv ip_rule \
inner join ./loc_db_only_jp.csv loc_jp \
on ip_rule.geoname_id = loc_jp.geoname_id" > ip_block_jp.csvrequire 'csv'
require 'ipaddr'
require 'pathname'
ip_file = Pathname.new(ARGV[0])
ip_block_list = CSV.read('ip_block_jp.csv')
mapping = ip_block_list.map { |(ip_block, loc)| [IPAddr.new(ip_block), loc] }
mapping.sort_by! { |(ip_block, _)| ip_block.to_s.split('/', 2).last.to_i * -1 }
filename = "#{ip_file.dirname}/#{ip_file.basename('.*')}_with_location#{ip_file.extname}"
CSV.open(filename, "wb") do |csv|
CSV.foreach(ip_file) do |(ip)|
csv << [ip, mapping.find { |(ip_block, loc)| ip_block.include?(ip) }&.last]
end
endめっちゃ遅い
IPアドレス100件の処理に20秒くらい。 ブラウザ自動操作よりは速いかもだけど。 数万件(数千秒)とか待ちきれない。
※ 実行はMBP
ベンチマークして確認。
CSV.foreach(ip_file) do |(ip)|
csv << [ip, mapping.find { |(ip_block, loc)| ip_block.include?(ip) }&.last]
endmappingが約6万件。
日本のデータだけにしたけどまだ全部判定させてたら遅い。
123.123.123.0/24 とかの範囲を全部個別IPに展開してBigQueryに入れ(ry
IP Blockのマスク値が8より小さいデータは無い。
→IPアドレスの最初の8bitはマスクしても変わらない。
→IPが 123.x.y.z なら 123.a.b.c/m のものだけ見ればOK。
数万件の判定 → 数百〜数千件の判定
def first_byte(ip)
ip.to_s.split('.', 2).first
end
mapping = mapping.group_by { |(ip_block, loc)| first_byte(ip_block.to_s) }
...
CSV.foreach(ip_file) do |(ip)|
csv << [ip, mapping[first_byte(ip)].find { |(ip_block, loc)| ip_block.include?(ip) }&.last]
end
...判定部分: 20秒 → 0.3秒
前処理含めても以前の1/10以下の時間で完了。 (mappingのcsv読み込みに1秒くらいかかる。)
依頼自体はケータイのIPが判定できないので流れました。
(GPS情報使うらしいです。)